from datetime import datetime, timedelta, timezone
from typing import Any

from jose import JWTError, jwt
from passlib.context import CryptContext

from .config import settings

pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")


def create_access_token(subject: str | Any, expires_delta: timedelta | None = None) -> str:
  expires_delta = expires_delta or timedelta(minutes=settings.access_token_expire_minutes)
  to_encode = {"exp": datetime.now(tz=timezone.utc) + expires_delta, "sub": str(subject)}
  return jwt.encode(to_encode, settings.jwt_secret_key, algorithm=settings.algorithm)


def create_refresh_token(subject: str | Any, expires_delta: timedelta | None = None) -> str:
  expires_delta = expires_delta or timedelta(minutes=settings.refresh_token_expire_minutes)
  to_encode = {"exp": datetime.now(tz=timezone.utc) + expires_delta, "sub": str(subject)}
  return jwt.encode(to_encode, settings.jwt_refresh_secret_key, algorithm=settings.algorithm)


def verify_password(plain_password: str, hashed_password: str) -> bool:
  return pwd_context.verify(plain_password, hashed_password)


def get_password_hash(password: str) -> str:
  return pwd_context.hash(password)


def decode_token(token: str, refresh: bool = False) -> dict[str, Any]:
  secret = settings.jwt_refresh_secret_key if refresh else settings.jwt_secret_key
  try:
    return jwt.decode(token, secret, algorithms=[settings.algorithm])
  except JWTError as exc:
    raise ValueError("Token 无效或已过期") from exc
